#include "AzModel.h"

#include <QDebug>

#include "AzRootRecord.h"
#include "AzAbstractDataSource.h"

/*!
	Constructor AzModel with a given \a parent
*/
AzModel::AzModel(QObject * parent) :QAbstractItemModel(parent),mDataSource(0),mIsOpen(false) {
    mRootRec = new AzRootRecord();
}

/*!
	Destructor AzModel
*/
AzModel::~AzModel() {
	delete mRootRec;

}

/*!
    Return the base item from the \a index. if \a index is not valid return 0.
    \Warning internalPointer must have valid object
*/
const AzRecord* AzModel::record(const QModelIndex &index) const
{
    if (index.isValid()) {
        AzRecord *item = static_cast<AzRecord*>(index.internalPointer());
        //debug !! реализовать проверку дебага
        if (!item)
            qFatal("AzModel::ModelElement has no object!");
        return item;
    }
    return 0;
}

/*!
    Return the base item from the \a index. if \a index is not valid return 0.
    \Warning internalPointer must have valid object
*/
AzRecord* AzModel::record(const QModelIndex &index) {
    if (index.isValid()) {
        AzRecord *item = static_cast<AzRecord*>(index.internalPointer());
        //debug !! реализовать проверку дебага
        if (!item)
            qFatal("AzModel::ModelElement has no object!");
        return item;
    }
    return 0;
}


/*!
	Returns the index of the item in the model specified by the given row, column and parent index.
*/

QModelIndex AzModel::index(int row, int column, const QModelIndex & parent) const
{
	if (!hasIndex(row, column, parent))
		return QModelIndex();

    const AzRecord *parentRec;
    if (!parent.isValid())
        parentRec = mRootRec;
    else {
        parentRec = static_cast<const AzRecord*>(parent.internalPointer());
    }
    AzRecord *childRec = parentRec->chaild(row);
    return createIndex(row, column, childRec);
}

/*!
Returns the parent of the model item with the given index. If the item has no parent, an invalid QModelIndex is returned.
*/
QModelIndex	AzModel::parent(const QModelIndex & index) const {
	if (!index.isValid())
		return QModelIndex();

    AzRecord* rec = static_cast<AzRecord*>(index.internalPointer());
    AzRecord* parentRec = rec->parent();
    return createIndex(rec->childNumber(),0,parentRec);
}

/*!
Return row count
\sa columnCount()
*/

int AzModel::rowCount(const QModelIndex & parent) const {
    if (!parent.isValid())
        return mRootRec->childCount();
    else {
        return static_cast<AzRecord*>(parent.internalPointer())->childCount();
    }
}

/*!
	Return column count stored in mRootRec.
*/
int	AzModel::columnCount(const QModelIndex &) const {
	return mRootRec->size();
}

/*!
Returns the data stored under the given role for the item referred to by the index.
*/

QVariant AzModel::data(const QModelIndex & index, int role) const
{
	if (!index.isValid())
		return QVariant();

	if (role != Qt::DisplayRole && role != Qt::EditRole)
		return QVariant();
	if (index.column() >= mRootRec->size())
		return QVariant("Out of index");

    const AzRecord *rec = record(index);
    if (rec->rootRec()->fields().field(index.column()).fieldKind() == AzField::CalcFieldKind) {
        QVariant val;
        emit calcField(index,val);
        return val;
    }
	return rec->data(index.column());
}

/*!
	Set data of the item
*/
bool AzModel::setData(const QModelIndex & index, const QVariant & value, int role) {
	if (role != Qt::EditRole && role != Qt::CheckStateRole)
		return false;
    AzRecord *rec = record(index);
	rec->setData(index.column(), value);
	emit dataChanged(index, index);
	return true;
}

/*!
	Returns the item flags for the given index.
*/
Qt::ItemFlags AzModel::flags(const QModelIndex & index) const {
	if (!index.isValid())
		return 0;

//	if (mRootRec->isReadOnly())
//		return Qt::ItemIsSelectable | Qt::ItemIsEnabled;

	return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
}

/*!
	Returns the data for the given role and section in the header with the specified orientation.
	The Header data stored in the mRootRec - root element of tree. Data stored only for orientation - Qt::Horizontal
*/
QVariant AzModel::headerData(int section, Qt::Orientation orientation, int role) const {
	if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        const  AzFieldList& fields = mRootRec->fields();
        return fields[section].displayName().isNull() ? fields[section].name() : fields[section].displayName();
	}
	return QVariant();
}

bool AzModel::open() {
   if (!mDataSource)
       return false;
   try {
        mDataSource->open();
   }
   catch (const AzError &e) {
        #ifdef AZ_DEBUG
            qDebug() << "open model error" << e.message();
        #endif
       return false;
    }

   AzFieldList fl = mDataSource->fields();
   mRootRec->fields() = fl;

   mIsOpen = true;
   return true;
}

AzAbstractDataSource* AzModel::dataSource() const {
    return mDataSource;
}

void AzModel::setDataSource(AzAbstractDataSource* source) {
    if (mDataSource)
        disconnect(source,SIGNAL(destroyed()),this,SLOT(sourceDestroyed()));
    mDataSource = source;
    if (mDataSource)
        connect(source,SIGNAL(destroyed()),this,SLOT(sourceDestroyed()));
}

void AzModel::sourceDestroyed() {
  mDataSource = 0;
}
